package com.android.readcard.utils.djlm.newDJMLReader;

import android.util.Log;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * Created by Administrator on 2017/3/9.
 */
/*
加速缓冲类
 */
public class DJLM_AccelerateCache extends Thread {


    private boolean m_bStop = true;
    private DJLM_TempCache m_TempCache;
    private String m_strAccelerateType = "";
    private boolean m_bServer;
    private int m_nTimeout;
    private IOException m_e;

    void LogOut(String strTest)
    {
        Log.i("AccelerateCache", strTest);
        //log.info(strTest);
        //System.out.println(strTest);
    }

    DJLM_AccelerateCache(boolean bServer, String strAccelerateType, int nTimeout)
    {
        m_TempCache = new DJLM_TempCache();
        m_TempCache.ConverToSZ();
        m_nTimeout = nTimeout;
        if (strAccelerateType != null && !strAccelerateType.isEmpty())
            m_strAccelerateType = strAccelerateType;
        m_bServer = bServer;
        //////////////////////////////////////////////////
        InitCache();
    }

    private DJLM_CardDeviceIO mCardDeviceIO = null;
    void SetTransChannel(DJLM_CardDeviceIO cardDeviceIO)
    {
        mCardDeviceIO = cardDeviceIO;
    }
    public void InitCache()
    {
        synchronized(this) {
            m_e = null;
            m_bStop = false;
            m_nCurrentQueryStep = 0;
            //指令运行的步骤状态
            m_nCurrentSendStep = 0;
            m_nCurrentRecvStep = 0;
            //缓冲线程是否正在运行
            m_bCommandListRuning = true;
            //指令缓冲是否已获取完整
            m_bCommandListComplete = false;
            if (m_commandList == null) {
                m_commandList = new ArrayList<DJML_CommandItem>();
                m_cacheData = DJML_CommandItem.InitCommandList(m_commandList);
            } else {
                for (int i = 0; i < commandListSize(); i++) {
                    GetStep(i).m_nComandState = GetStep(i).m_nDefaultState;
                    GetStep(i).m_Response = null;
                }
            }
            RefreshTick();
        }
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        LogOut("Accelerate Start!" + m_strAccelerateType);
        m_bStop = false;
        if (mCardDeviceIO != null)
            RunCommandList();
        super.run();
    }

    /*
    启动
     */
    public void Start()
    {
        RefreshTick();
        start();
    }

    /*
    停止
     */
    public void Stop()
    {
        LogOut("Accelerat Stop!");
        m_bStop = true;
        synchronized(this)
        {
            notifyAll();
        }
        interrupt();
        try {
            join();
        }catch (InterruptedException e)
        {
        }
        LogOut("Accelerat Exit!");
    }

    public boolean IsRuning()
    {
        return m_bCommandListRuning;
    }

    long m_nStartTick = 0;
    public void RefreshTick()
    {
        m_nStartTick = System.currentTimeMillis();
    }

    public boolean IsChannelOverdueTick()
    {
        if (m_bCommandListRuning)
            return System.currentTimeMillis() >= m_nStartTick + m_nTimeout;
        return true;
    }

    /*
	网络数据包请求
	query:请求的数据内容  可为null
	返回值返回的数据  若无数据返回，则返回null
    */
    public byte[] InEtherPack(byte[] query) throws IOException
    {
        byte[] ret = null;
        ret = GetCacheResponse(query);
        return ret;
    }

    byte[] m_lastQuery = null; //最近一次网络请求数据
    byte[] m_lastRespone =  null; //最近一次返回的数据
    long m_nLastTime = 0;//最近一次数据请求的时间
    /*
	该函数暂不使用
    */
    public byte[] InEtherPack(byte[] query, int nDelayTime, long nTimestamp) throws IOException
    {
        byte[] ret = null;
        long nBeginTime = System.currentTimeMillis();
        ret = GetCacheResponse(query);
        if (query != null)
        {
            if (Arrays.equals(m_lastQuery, query))
            {
                if (ret != null && Arrays.equals(m_lastRespone, ret) && ((System.currentTimeMillis() - nTimestamp) < 3)
                        && !Arrays.equals(query, m_TempCache.FindCard) && !Arrays.equals(query, m_TempCache.SelectCard))
                {
                    LogOut("cumu ignore");
                    return null;
                }
            }
            else
            {
                m_lastQuery = query;
                m_nLastTime = nTimestamp;
                //LogOut("save Timestamp" + nTimestamp);
            }
        }
        if (ret != null)
            m_lastRespone = ret;
        /////////////////////////////////////////////
        if (ret != null)
        {
            int nDelayTicket = GetDelayTicket();
            //LogOut("nBeDelayTicket = " + nBeDelayTicket);
            long nSleep = m_nLastTime + nDelayTicket - System.currentTimeMillis();
            if (nSleep > 0 )
            {
                LogOut("=====Delay" + nSleep + "=====");
                try {
                    Thread.sleep(nSleep);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        return ret;
    }

    /*
    该函数暂不使用
     */
    public int GetDelayTicket()
    {
        int nDelayTicket;
        synchronized(this)
        {
            if (!m_bCommandListComplete)
            {
                nDelayTicket = 230;
                if (GetCurrentQueryStep().m_nCommandType == DJML_CommandItem.COMMAND_FIND_CARD)
                    nDelayTicket = 0;
                else if (GetCurrentQueryStep().m_nCommandType == DJML_CommandItem.COMMAND_SELECT_CARD)
                    nDelayTicket = 0;
            }
            else
            {
                nDelayTicket = 0;
            }
        }
        return nDelayTicket;
    }

    //指令列表
    List<DJML_CommandItem> m_commandList;
    byte[] m_cacheData = null;
    //指令请求的步骤状态
    int m_nCurrentQueryStep = 0;
    //指令运行的步骤状态
    int m_nCurrentSendStep = 0;
    int m_nCurrentRecvStep = 0;
    //缓冲线程是否正在运行
    boolean m_bCommandListRuning = false;
    //指令缓冲是否已获取完整
    boolean m_bCommandListComplete = false;
    //初始化指令列表

    //获取当前请求的对应的指令列表项
    DJML_CommandItem GetCurrentQueryStep()
    {
        DJML_CommandItem commChannel = m_commandList.get(m_nCurrentQueryStep);
        return commChannel;
    }

    DJML_CommandItem GetStep(int nStep)
    {
        DJML_CommandItem commChannel = m_commandList.get(nStep);
        return commChannel;
    }

    int commandListSize()
    {
        return m_commandList.size();
    }

    boolean GoToFirstStep(byte[] query)
    {
        int nNewStep = m_nCurrentQueryStep;
        if (Arrays.equals(query, m_TempCache.FindCard))
        {
            if (m_nCurrentQueryStep > 0)
            {
                if (GetStep(0).m_nQueryCount > 3)
                    nNewStep = 0;
                else
                    GetStep(0).m_nQueryCount++;
            }
        }
        if (Arrays.equals(query, m_TempCache.SelectCard))
        {
            if (m_nCurrentQueryStep > 1)
            {
                if (GetStep(1).m_nQueryCount > 2)
                    nNewStep = 1;
                else
                    GetStep(1).m_nQueryCount++;
            }
        }

        if (Arrays.equals(query, m_TempCache.SelectFile6002))
        {
            if (m_nCurrentQueryStep > 2)
            {
                nNewStep = 2;
            }
        }

        if (nNewStep != m_nCurrentQueryStep)
        {
            m_nCurrentQueryStep = nNewStep;
            m_nCurrentSendStep = nNewStep;
            m_nCurrentRecvStep = nNewStep;
            for (int i = nNewStep; i < commandListSize(); i++)
            {
                GetStep(i).m_nComandState = GetStep(i).m_nDefaultState;
                GetStep(i).m_Response = null;
            }
            notifyAll();
            LogOut("init to first step");
            return true;
        }
        return false;
    }
    ////////////////////////////////////////
    //根据当前请求内容切换到下一步骤
    boolean  QueryNextStep(byte [] query)  throws IOException
    {
        synchronized(this)
        {
            if (GoToFirstStep(query))
                return true;
            int nNewStep = m_nCurrentQueryStep;
            DJML_CommandItem curDJML_CommandItem = GetCurrentQueryStep();
            if (!Arrays.equals(query, curDJML_CommandItem.m_Query))
            {
                if (Arrays.equals(query, m_TempCache.SelectFile6002) && curDJML_CommandItem.m_nCommandType == DJML_CommandItem.COMMAND_FIND_CARD)
                    nNewStep = m_nCurrentQueryStep + 2;
                else
                    nNewStep = m_nCurrentQueryStep + 1;

                {
                    if (nNewStep < commandListSize()) {
                        DJML_CommandItem commandItem = GetStep(nNewStep);
                        if (commandItem.QueryMatch(query)) {
                            if (commandItem.m_nComandState == DJML_CommandItem.STATE_COMMAND_NOREADY) {
                                commandItem.m_Query = query;
                                commandItem.m_nComandState = DJML_CommandItem.STATE_COMMAND_READY;
                                commandItem.m_nQueryCount = 0;
                                commandItem.m_nRunCount = 0;
                                commandItem.m_Response = null;
                            }
                            commandItem.m_nQueryCount = 0;
                            m_nCurrentQueryStep = nNewStep;
                            notifyAll();
                            return true;
                        }
                        else
                        {
                            LogOut("Query not Match;" + commandItem.GetDebugString(commandItem.m_Query) + "-"+ nNewStep  + " " + commandItem.GetDebugString(query));
                            return false;
                        }
                    }
                }
            }
            return  true;
        }
    }

    //请求缓存中的数据
    byte[] QueryCache(byte query[]) throws IOException
    {
        byte ret[] = null;
        synchronized(this)
        {
            DJML_CommandItem commandItem = GetCurrentQueryStep();
            if (commandItem.GetSatet() == commandItem.STATE_COMMAND_FINISH)
            {
                if (query != null || commandItem.m_nCommandType != DJML_CommandItem.COMMAND_FIND_CARD)
                {
                    commandItem.NextState();
                    if (query != null)
                        commandItem.m_nQueryCount++;
                    if (!m_bServer && m_strAccelerateType.equals("block"))
                        ret = MakeBatchResponse(m_nCurrentQueryStep);
                    else
                        ret = commandItem.m_Response;
                }
            }
            else if (commandItem.GetSatet() == DJML_CommandItem.STATE_COMMAND_USEED)
            {
                if (query != null)
                {
                    commandItem.m_nQueryCount++;
                    if (!m_bServer && m_strAccelerateType.equals("block"))
                        ret = DJLM_BatchResponse.MakeSinglehResponse(commandItem.m_Response, commandItem.m_Query, commandItem.m_nStep);
                    else
                        ret = commandItem.m_Response;
                }
            }
            else if (query != null)
            {
                commandItem.m_nQueryCount++;
                if (commandItem.m_Response != null) {
                    if (!m_bServer && m_strAccelerateType.equals("block"))
                        ret = DJLM_BatchResponse.MakeSinglehResponse(commandItem.m_Response, commandItem.m_Query, commandItem.m_nStep);
                    else
                        ret = commandItem.m_Response;
                }
            }
            if (commandItem.GetSatet() > DJML_CommandItem.STATE_COMMAND_USEED)
            {
                LogOut("State Error! break! 1" + commandItem.GetSatet());
                if (m_e != null)
                    throw m_e;
                throw new IOException("State Error");
            }
        }
        return ret;
    }

    byte[] MakeBatchResponse(int nBeginSetp)
    {
        //int nBeginSetp = m_nCurrentQueryStep;
        int nEndStep = m_nCurrentQueryStep;
        int nRecvStep = m_nCurrentRecvStep;
        DJLM_BatchResponse batchResponse = new DJLM_BatchResponse(1450);
        for (int i = nBeginSetp;i <= nRecvStep && i < commandListSize(); i++)
        {
            DJML_CommandItem commandItem = GetStep(i);
            if ((commandItem.m_nComandState == DJML_CommandItem.STATE_COMMAND_USEED || commandItem.m_nComandState == DJML_CommandItem.STATE_COMMAND_FINISH) && commandItem.m_Response != null) {
                //if (DJML_CommandItem.m_Response != null && DJML_CommandItem.m_Response.length > 0) {
                if (commandItem.IsResponseOK()) {
                    if (batchResponse.AddResponse( commandItem.m_Response, commandItem.m_Query, commandItem.m_nStep) > 0)
                    {
                        commandItem.m_nComandState = DJML_CommandItem.STATE_COMMAND_USEED;
                        nEndStep = i;
                        LogOut("m_nCurrentQueryStep goto " + commandItem.GetDebugString(commandItem.m_Query));
                    }else
                        break;
                }
                else if (commandItem.m_nCommandType == DJML_CommandItem.COMMAND_FIND_CARD && commandItem.m_Response != null && commandItem.m_Response.length == 0)
                {
                    return commandItem.m_Response;
                }
            }
            else
                break;
        }
        if (nEndStep > m_nCurrentQueryStep)
            m_nCurrentQueryStep = nEndStep;
        return batchResponse.GetBatchResponse();
    }

    //请求缓存数据，并根据需要切换步骤
    byte[]  GetCacheResponse(byte query[]) throws IOException
    {
        byte ret[] = null;
        if (!m_bCommandListRuning && !m_bCommandListComplete) {
            if (m_e != null)
                throw m_e;
            else
                throw new IOException("End");
        }

        int nStep = -1;
        /////////////////////////////////////////////////////
        if (query != null) {
            int nEnd = -1;
            for (int i = 2; i < query.length; i++) {
                if (!((query[i] >= '0' && query[i] <= '9') || (query[i] >= 'a' && query[i] <= 'f') || (query[i] >= 'A' && query[i] <= 'F')) && query[1] != '\n') {
                    nEnd = i + 1;
                    break;
                }
            }
            if (query.length >= nEnd + 1)
            {
                byte [] szStep = Arrays.copyOfRange(query, nEnd, query.length - 1);
                String strStep = new String(szStep);
                nStep = Integer.parseInt(strStep);
                query = Arrays.copyOf(query, nEnd);
                query[query.length - 1] = '\n';
            }
        }
        ////////////////////////////////////////////////////
        {
            if (!m_bServer && m_strAccelerateType.equals("block"))
            {
                synchronized(this)
                {
                    if (query != null && nStep >= 0 ) {
                        GoToFirstStep(query);
                        DJML_CommandItem commandItem = GetStep(nStep);
                        if (commandItem.m_nComandState == DJML_CommandItem.STATE_COMMAND_NOREADY) {
                            commandItem.m_Query = query;
                            commandItem.m_nComandState = DJML_CommandItem.STATE_COMMAND_READY;
                            notifyAll();
                        }
                        //////////////////////////////////////////////////////
                        GetStep(nStep).m_nQueryCount++;
                        if (GetStep(nStep).m_nQueryCount >= 2) {
                            if (GetStep(nStep).m_nComandState >= DJML_CommandItem.STATE_COMMAND_FINISH && GetStep(nStep).IsResponseOK()) {
                                //ret = BatchResponse.MakeSinglehResponse(GetStep(nStep).m_Response, GetStep(nStep).m_Query, GetStep(nStep).m_nStep);
                                ret = MakeBatchResponse(nStep);
                            }
                        }
                    } else {
                        if (GetStep(m_nCurrentQueryStep).GetSatet() > DJML_CommandItem.STATE_COMMAND_FINISH) {
                            if (m_nCurrentQueryStep + 1 < commandListSize() && GetStep(m_nCurrentQueryStep + 1).GetSatet() >= DJML_CommandItem.STATE_COMMAND_FINISH) {
                                m_nCurrentQueryStep++;
                            }
                        }
                        if (GetStep(m_nCurrentQueryStep).GetSatet() == DJML_CommandItem.STATE_COMMAND_FINISH)
                            ret = MakeBatchResponse(m_nCurrentQueryStep);
                    }
                }
            }
            else
            {
                if (query != null) {
                    if (!QueryNextStep(query))
                        return null;
                }
                ret = QueryCache(query);
            }
        }
        return ret;
    }
    ///////////////////////////////////////////
    void RunCommandList()
    {
        m_nCurrentSendStep = 0;
        m_nCurrentRecvStep = 0;
        for(;;)
        {
            synchronized(this)
            {
                if (m_bStop || m_nCurrentRecvStep >= commandListSize() || m_bCommandListComplete)
                    break;
                if (IsChannelOverdueTick())
                {
                    LogOut("AccelerateCache timeout break.");
                    m_e = new IOException("AccelerateCache timeout break.");
                    break;
                }
            }
            try{
                byte[] query = null;
                byte[] response = null;
                query = GetCommandQuery(m_nCurrentRecvStep);
                if (query != null)
                    response = DoDeviceIO(query, m_nCurrentRecvStep, 200);
                else {
                    if (m_bServer) {
                        response = DoDeviceIO(query, -1, 0);
                    }
                    else
                    {
                        DoDeviceIO(query, -1, 0);
                    }
                }
                if (response != null)
                    RefreshTick();
                if (query != null || response != null)
                {
                    if (HandleBatchResponse(query, response))
                        break;
                }
            } catch (IOException e) {
                // TODO Auto-generated catch block
                m_e = e;
                e.printStackTrace();
                break;
            }
            if (RunToNextStep())
                break;
        }
        if (m_nCurrentRecvStep >= commandListSize() || m_bCommandListComplete)
        {
            m_bCommandListComplete = true;
            LogOut("-----------cache complet!--------------");
        }
        else
            LogOut("-----------cache break!--------------");
        m_bCommandListRuning = false;
    }

    boolean RunToNextStep()
    {
        boolean bComplete = false;
        synchronized(this)
        {
            if (Arrays.equals(GetStep(m_nCurrentRecvStep).m_Response, m_TempCache.ReadNullResponse) && Arrays.equals(GetStep(m_nCurrentRecvStep).m_Query,m_TempCache.ReadBinary0Query))
            {
                LogOut("CommandListComplete!");
                m_bCommandListComplete = true;
                bComplete = true;
            }
            if (m_nCurrentRecvStep + 1 == commandListSize())
            {
                if (GetStep(m_nCurrentRecvStep).m_nComandState >= DJML_CommandItem.STATE_COMMAND_FINISH && GetStep(m_nCurrentRecvStep).IsResponseOK())
                {
                    LogOut("CommandListComplete!");
                    m_bCommandListComplete = true;
                    bComplete = true;
                }
            }
            if (m_nCurrentRecvStep >= commandListSize())
            {
                LogOut("CommandListComplete!");
                m_bCommandListComplete = true;
                bComplete = true;
            }
            if (!bComplete)
            {
                if (GetStep(m_nCurrentRecvStep).m_nComandState >= DJML_CommandItem.STATE_COMMAND_FINISH)
                {
                    //if ( GetStep(m_nCurrentRecvStep).m_Response != null && GetStep(m_nCurrentRecvStep).m_Response.length > 0)
                    if (GetStep(m_nCurrentRecvStep).IsResponseOK())
                    {
                        System.arraycopy(GetStep(m_nCurrentRecvStep).m_Response, 0, m_cacheData, GetStep(m_nCurrentRecvStep).m_nCachePos, GetStep(m_nCurrentRecvStep).m_nResponseLen);
                        if (m_nCurrentRecvStep + 1 < commandListSize())
                            m_nCurrentRecvStep++;
                    }
                }
            }
        }
        return bComplete;
    }

    boolean HandleBatchResponse(byte[] query, byte[] response) throws IOException
    {
        boolean bGoNext = false;
        boolean bComplete = false;
        boolean bBuilderResponse = false;
        synchronized(this)
        {
            //LogOut("BatchResponse ret:" + HexUtil.bytesToHexString(response));
            //if (!m_bServer || (!m_strAccelerateType.equals("block")))
            {
                if (query != null && response == null && GetStep(m_nCurrentRecvStep).m_bFixResponse != null)
                {
                    //response = GetStep(m_nCurrentRecvStep).m_bFixResponse;
                    //bBuilderResponse = true;
                    //LogOut("builder response" +  GetStep(m_nCurrentRecvStep).GetDebugString(response));
                }
            }
            if (response != null)
            {
                if (response != null && response.length == 0)
                {
                    ResponseToNext(m_nCurrentRecvStep, response, null);
                }
                DJLM_BatchResponse batchResponse = new DJLM_BatchResponse(response);
                byte [] thisResponse = null;
                DJML_CommandItem retDJML_CommandItem = null;
                while((retDJML_CommandItem = batchResponse.GetNextResponse()) != null)
                {
                    thisResponse = retDJML_CommandItem.m_Response;
                    if (query != null && GetStep(m_nCurrentRecvStep).GetSatet() == DJML_CommandItem.STATE_COMMAND_READY)
                    {
                        GetStep(m_nCurrentRecvStep).m_nComandState = DJML_CommandItem.STATE_COMMAND_RUNING;
                    }

                    if (retDJML_CommandItem.m_nStep != -1)
                    {
                        DJML_CommandItem commandItem = null;
                        commandItem = GetStep(retDJML_CommandItem.m_nStep);
                        if (!commandItem.IsResponseOK(retDJML_CommandItem.m_Response))
                        {
                            if (commandItem.m_bFixResponse != null) {
                                //LogOut("rescue response "+ DJML_CommandItem.GetDebugString(response) + " " + DJML_CommandItem.GetDebugString(DJML_CommandItem.m_Query));
                                //retDJML_CommandItem.m_Response = DJML_CommandItem.m_bFixResponse;
                            }
                        }
                        retDJML_CommandItem.m_Response = m_TempCache.FixResponse(retDJML_CommandItem.m_Query, retDJML_CommandItem.m_Response);
                        commandItem.m_Response = retDJML_CommandItem.m_Response;
                        if (retDJML_CommandItem.m_nStep == 22)
                            commandItem.m_Response = m_TempCache.Select6011LastRet;
                        if (retDJML_CommandItem.m_nStep >= 106)
                            commandItem.m_Response = m_TempCache.ReadNullResponse;
                        if (commandItem.m_nComandState != DJML_CommandItem.STATE_COMMAND_USEED)
                            commandItem.m_nComandState = DJML_CommandItem.STATE_COMMAND_FINISH;
                    }
                    else
                    {
                        thisResponse = m_TempCache.FilterCrossResponse(query, thisResponse);
                        m_TempCache.RecordQueryRespone(query, thisResponse);
                        thisResponse = m_TempCache.FixResponse(query, thisResponse);
                        bGoNext = ResponseToNext(m_nCurrentRecvStep, thisResponse, retDJML_CommandItem.m_Query);
                    }
                    if (!bBuilderResponse)
                    {
                        if (RunToNextStep())
                        {
                            bComplete = true;
                            break;
                        }
                    }
                }
                notifyAll();
            }
        }
        return bComplete;
    }

    //运行当前指令，返回是否切换至下一命令
    long m_nLastSendTime = 0;
    byte[] GetCommandQuery(int nStep)
    {
        byte[] query = null;
        boolean bGoNext = false;
        DJML_CommandItem commandItem = null;
        int nCommandState;
        boolean bRun = false;
        synchronized(this)
        {
            if (nStep < commandListSize())
            {
                commandItem = GetStep(nStep);
                if (commandItem.GetSatet() == DJML_CommandItem.STATE_COMMAND_NOREADY)
                {
                    try {
                        wait(200);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }

                if ((commandItem.GetSatet() == DJML_CommandItem.STATE_COMMAND_FINISH || commandItem.GetSatet() == DJML_CommandItem.STATE_COMMAND_USEED))
                {
                    if  (commandItem.m_nCommandType != DJML_CommandItem.COMMAND_GET_CHALLENGE && commandItem.m_nCommandType != DJML_CommandItem.COMMAND_EXTERNAL_AUTHENTICATE)
                    {
                        commandItem.m_nComandState = DJML_CommandItem.STATE_COMMAND_RUNING;
                        bRun = true;
                    }
                    if (commandItem.m_nCommandType == DJML_CommandItem.COMMAND_FIND_CARD)
                    {
                        commandItem.m_nComandState = DJML_CommandItem.STATE_COMMAND_RUNING;
                        bRun = true;
                    }
                }
                else if (commandItem.GetSatet() == DJML_CommandItem.STATE_COMMAND_READY)
                {
                    commandItem.m_nComandState = DJML_CommandItem.STATE_COMMAND_RUNING;
                    bRun = true;
                }
                else if (commandItem.GetSatet() == DJML_CommandItem.STATE_COMMAND_RUNING)
                {
                    if (!m_bServer || System.currentTimeMillis() > m_nLastSendTime + 200 )
                    {
                        if  (commandItem.m_nCommandType != DJML_CommandItem.COMMAND_GET_CHALLENGE && commandItem.m_nCommandType != DJML_CommandItem.COMMAND_EXTERNAL_AUTHENTICATE)
                            bRun = true;
                        if (commandItem.m_nCommandType == DJML_CommandItem.COMMAND_FIND_CARD)
                            bRun = true;
                    }
                }
                if (bRun)
                {
                    query = Arrays.copyOf(commandItem.m_Query, commandItem.m_Query.length);
                    commandItem.m_nRunCount++;
                }
            }
        }
        if (query != null)
            m_nLastSendTime = System.currentTimeMillis();
        return query;
    }

    //////////////////////////////////////////////////////
    byte[] DoDeviceIO(byte[] query, int nStep,  int nTimeout) throws IOException
    {
        byte[] response = null;
        if (m_bServer && m_strAccelerateType.equals("block")) {
            if (query != null && query.length > 3 && nStep >= 0) {
                String strAdd = "-" + nStep;
                byte[] szAdd = strAdd.getBytes();
                byte[] newQuery = new byte[query.length + szAdd.length];
                System.arraycopy(query, 0, newQuery, 0, query.length);
                System.arraycopy(szAdd, 0, newQuery, query.length - 1, szAdd.length);
                newQuery[newQuery.length - 1] = '\n';
                query = newQuery;
            }
        }

        if (response == null)
        {
            {
                long nBeginTime = 0;
                boolean bSkip = false;
                do
                {
                    nBeginTime = System.currentTimeMillis();
                    //if (!bSkip && query != null)
                    //	mCardDeviceIO.DeviceIOOut(query);
                    //response = mCardDeviceIO.DeviceIOIn(nTimeout);

                    if (bSkip)
                        response = mCardDeviceIO.DeviceIOPort(null, nTimeout);
                    else
                        response = mCardDeviceIO.DeviceIOPort(query, nTimeout);

                    if (System.currentTimeMillis() - nBeginTime < 5 && response != null && m_TempCache.FilterCrossResponse(query, response) == null)
                        bSkip = true;
                    else
                        break;
                }while(true);
            }
            return response;
        }
        return null;
    }

    boolean ResponseToNext(int nStep, byte[] response, byte[] query) throws IOException
    {
        boolean bGoNext = false;
        DJML_CommandItem commandItem = null;
        commandItem = GetStep(nStep);
        if (commandItem.GetSatet() == DJML_CommandItem.STATE_COMMAND_READY)
        {
            commandItem.m_nComandState = DJML_CommandItem.STATE_COMMAND_RUNING;
        }
        if (commandItem.GetSatet() == DJML_CommandItem.STATE_COMMAND_RUNING)
        {

            if (commandItem.m_nCommandType == DJML_CommandItem.COMMAND_FIND_CARD)
            {
                if (Arrays.equals(response, m_TempCache.CardErrRet) && commandItem.IsResponseOK())
                {
                    response = commandItem.m_Response;
                    LogOut("rescue FindCard");
                }
            }
            if (!commandItem.IsResponseOK(response))
            {
                if (commandItem.m_bFixResponse != null) {
                    //LogOut("rescue response "+ DJML_CommandItem.GetDebugString(response) + " " + DJML_CommandItem.GetDebugString(DJML_CommandItem.m_Query));
                    //response = DJML_CommandItem.m_bFixResponse;
                }
            }
            //////////////////////////////////////////
            commandItem.m_Response = response;
            if (m_nCurrentRecvStep == 22)
                commandItem.m_Response = m_TempCache.Select6011LastRet;
            if (m_nCurrentRecvStep >= 106)
                commandItem.m_Response = m_TempCache.ReadNullResponse;
            if (commandItem.m_Response != null) {
                commandItem.NextState();
                //if (DJML_CommandItem.m_Response.length > 0) {
                if (commandItem.IsResponseOK()) {
                    bGoNext = true;
                }
            }
        }
        /////////////////////////////////////////////////
        if (commandItem.GetSatet() > DJML_CommandItem.STATE_COMMAND_USEED)
        {
            LogOut("State Error! break! 1" + commandItem.GetSatet());
            throw new IOException("Response Error");
        }
        return bGoNext;
    }
}
